﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#include "CLEvent.h"

namespace UX_STL
{
namespace CLShell
{

/*
=================================================
	конструктор
=================================================
*/
	CLEvent::CLEvent():
		_pID(null), _pCallback(null)
	{
	}
	
	CLEvent::CLEvent(cl_event pEvent):
		_pID(pEvent), _pCallback(null)
	{
	}

/*
=================================================
	деструктор
=================================================
*/
	CLEvent::~CLEvent()
	{
	}
	
/*
=================================================
	создать объект события
=================================================
*/
	bool CLEvent::Create(ICLEventCallback *pCallback)
	{
		Destroy();

		cl_int	i_cl_err = 0;

		CL_CALL_R( _pID = clCreateUserEvent( CLDEVICE()->Context(), &i_cl_err ) );
		CL_CALL_R( i_cl_err = clSetEventCallback( _pID, CL_COMPLETE, &_s_Callback, this ) );
		
		SetCallback( pCallback );
		return true;
	}
	
/*
=================================================
	удалить объект события
=================================================
*/
	void CLEvent::Destroy()
	{
		_ReleaseRef();
		_pID		= null;
		_pCallback	= null;
	}
	
/*
=================================================
	установить статус
=================================================
*/
	bool CLEvent::SetStatus(cl_event_status::type eType)
	{
		CHECK_ERR( eType != cl_event_status::QUEUED and
						eType != cl_event_status::RUNNING and
						eType != cl_event_status::SUBMITTED );

		cl_int	i_cl_err = 0;

		CL_CALL_R( i_cl_err = clSetUserEventStatus( _pID, eType ) );
		return true;
	}

/*
=================================================
	установить колбэк
=================================================
*/
	void CLEvent::SetCallback(ICLEventCallback *pCallback)
	{
		_pCallback = pCallback;
	}
	
/*
=================================================
	ожидать пока не сработает событие
=================================================
*/
	bool CLEvent::Wait() const
	{
		return clWaitForEvents( 1, &_pID ) == CL_SUCCESS;
	}
	
/*
=================================================
	ожидать пока не сработают все события
=================================================
*/
	bool CLEvent::s_Wait(const clevent_uni_array &aEvents)
	{
		return clWaitForEvents( (cl_uint) aEvents.Count(), aEvents.ptr() ) == CL_SUCCESS;
	}

/*
=================================================
	вызвать колбэк
=================================================
*/
	void CALLBACK CLEvent::_s_Callback(cl_event pEvent, cl_int iStatus, void *pUserData)
	{
		CLEvent	*ev = (CLEvent *)pUserData;

		if ( pEvent == ev->_pID and ev->_pCallback != null )
			(*ev->_pCallback)( ev, (cl_event_status::type)iStatus );
	}

/*
=================================================
	возвращает тип команды
=================================================
*/
	bool CLEvent::GetCommandType(cl_event_command::type &eType) const
	{
		cl_command_type		u_command	= 0;
		cl_int				i_cl_err	= 0;

		CL_CALL_R( i_cl_err = clGetEventInfo( _pID, CL_EVENT_COMMAND_TYPE, sizeof(u_command), &u_command, null ) );
		
		eType = (cl_event_command::type)u_command;
		return true;
	}
	
/*
=================================================
	возвращает статус
=================================================
*/
	bool CLEvent::GetStatus(cl_event_status::type &eType) const
	{
		cl_int	i_status = 0;
		cl_int	i_cl_err = 0;

		CL_CALL_R( i_cl_err = clGetEventInfo( _pID, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(i_status), &i_status, null ) );
		
		eType = (cl_event_status::type)i_status;
		return true;
	}
	
/*
=================================================
	возвращает время в наносекундах
=================================================
*/
	bool CLEvent::GetProfilingTime(cl_event_time::type eType, uint64 &uTime) const
	{
		cl_int		i_cl_err = 0;
		cl_ulong	result	 = 0;

		CL_CALL_R( i_cl_err = clGetEventProfilingInfo( _pID, eType, sizeof(result), &result, null ) );
		return true;
	}

	__UX_CL_RC_IMPL( CLEvent, _pID, Event, EVENT )

//-------------------------------------------------------------------

}	// CLShell
}	// UX_STL